#include"mainWindow.h"
using std::string;

void delay()
{
    QTime dieTime= QTime::currentTime().addSecs(1);
    while( QTime::currentTime() < dieTime )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

MainWindow::MainWindow():QMainWindow()
{

    QWidget *zoneCentrale = new QWidget();

    is_phase2 = 0;

    /*
      Création des instances composants la main window
      */
    zoneRotors = new Rotors();
    zoneLightBoard = new LightBoard();
    zonePlugBoard = new PlugBoard();
    log = new QLineEdit();
    in = new QLineEdit();
    in->setDisabled(true);
    in->hide();
    log->setReadOnly(true);
    layout_mainWindow = new QGridLayout();
    valider = new QPushButton("Valider");
    send = new QPushButton("Envoyer");
    send->hide();

    /*
      Initialisation partie interne
      */
    plugb = (Plugboard*) malloc(sizeof(Plugboard));
    plugb->connexions = (int**) malloc(sizeof(int*)*20);
    for (int i=0; i<20; i++)
        plugb->connexions[i]=(int*) malloc (sizeof(int)*2);



    /* déclaration des rotors, du réflecteur et du plugboard */
    rotor1 = (Rotor_intern*) malloc(sizeof(Rotor_intern));
    rotor1->encoche=12;

    rotor2 = (Rotor_intern*) malloc(sizeof(Rotor_intern));
    rotor2->encoche=16;

    rotor3 = (Rotor_intern*) malloc(sizeof(Rotor_intern));
    rotor3->encoche=8;

    refl = (Reflecteur*) malloc(sizeof(Reflecteur));

    /* emplacements pour les permutations */
    rotor1->sorties = (int*) malloc(sizeof(int)*26);
    rotor2->sorties = (int*) malloc(sizeof(int)*26);
    rotor3->sorties = (int*) malloc(sizeof(int)*26);
    refl->sorties = (int*) malloc(sizeof(int)*26);

    reset_rotor_intern();




    /* permutations du réflecteur */
    refl->sorties[0]=24;
    refl->sorties[1]=17;
    refl->sorties[2]=20;
    refl->sorties[3]=7;
    refl->sorties[4]=16;
    refl->sorties[5]=18;
    refl->sorties[6]=11;
    refl->sorties[7]=3;
    refl->sorties[8]=15;
    refl->sorties[9]=23;
    refl->sorties[10]=13;
    refl->sorties[11]=6;
    refl->sorties[12]=14;
    refl->sorties[13]=10;
    refl->sorties[14]=12;
    refl->sorties[15]=8;
    refl->sorties[16]=4;
    refl->sorties[17]=1;
    refl->sorties[18]=5;
    refl->sorties[19]=25;
    refl->sorties[20]=2;
    refl->sorties[21]=22;
    refl->sorties[22]=21;
    refl->sorties[23]=9;
    refl->sorties[24]=0;
    refl->sorties[25]=19;




    /*
      Partie layout
      */
    layout_mainWindow->addWidget(zoneRotors,0,0);
    layout_mainWindow->addWidget(zoneLightBoard,1,0);
    layout_mainWindow->addWidget(zonePlugBoard,2,0);
    layout_mainWindow->addWidget(in, 3,0);
    layout_mainWindow->addWidget(send, 3,1);
    layout_mainWindow->addWidget(log,4,0);
    layout_mainWindow->addWidget(valider,4,1);
    zoneCentrale->setLayout(layout_mainWindow);


    /*
    Partie Fenetre Principale
  */
    QMenu *menuFichier = menuBar()->addMenu("Fichier");
    QMenu *menuAPropos = menuBar()->addMenu("A Propos");

    QAction *actionNouveau = new QAction("Nouveau...", this);
    actionNouveau->setShortcut(QKeySequence("F2"));
    QAction *actionQuitter = new QAction("Quitter", this);
    QAction *actionAide = new QAction("Aide", this);
    actionAide->setShortcut(QKeySequence("F1"));
    QAction *actionPropos = new QAction("A propos...", this);

    menuFichier->addAction(actionNouveau);
    menuFichier->addAction(actionQuitter);
    menuAPropos->addAction(actionAide);
    menuAPropos->addAction(actionPropos);

    setCentralWidget(zoneCentrale);


    QObject::connect(valider, SIGNAL(clicked()), this, SLOT(verif_plugs()));
    QObject::connect(send,SIGNAL(clicked()), this, SLOT(clicked_on_send()));

    QObject::connect(this, SIGNAL(plugs_ok()), this, SLOT(clean()));

    QObject::connect(this, SIGNAL(free_ok()), qApp, SLOT(quit()));
    QObject::connect(actionQuitter, SIGNAL(triggered()), this, SLOT(free_and_quit()));
    QObject::connect(actionNouveau, SIGNAL(triggered()), this, SLOT(reload()));
    QObject::connect(actionAide, SIGNAL(triggered()), this, SLOT(help()));
    QObject::connect(actionPropos, SIGNAL(triggered()), this, SLOT(describe()));

}

void MainWindow::verif_plugs()
{
    nb_permutations = this->zonePlugBoard->nb_plugs_ok();
    if(nb_permutations > 2)
    {
        log->setText("");
        emit plugs_ok();
    }
    else
    {
        log->setText("Impossible de valider sans avoir au moins 3 permutations valides");
    }
}



void MainWindow::clicked_on_send()
{

    send->setVisible(false);
    int size = in->text().length();
    QString tmp;
    for(int i = 0; i < size;++i)
    {
        tmp = in->text()[i];
        load_enigma(QString_to_int(tmp));
        delay();
    }
    in->setText("");
    in->setDisabled(false);
    send->setVisible(true);
}


void MainWindow::clean()
{
    is_phase2 = 1; //passage en phase 2;
    this->zonePlugBoard->phase2_plugboard();
    this->zoneRotors->phase2_rotors();
    this->valider->setVisible(false);
    this->send->show();
    this->in->show();
    this->in->setEnabled(true);
    /*
      INITIALISER PLUGBOARD INTERNE
      */
    int tmp;
    int j = 0; //n° de la permu
    for(int i = 0; i < 20; i+=2)
    {
        if (this->zonePlugBoard->get_validite(i))
        {
            tmp = QString_to_int(this->zonePlugBoard->getPlug(i)->currentText());
            plugb->connexions[j][0] = tmp;
            plugb->connexions[j+1][1] = tmp;

            tmp = QString_to_int(this->zonePlugBoard->getPlug(i+1)->currentText());
            plugb->connexions[j][1] = tmp;
            plugb->connexions[j+1][0] = tmp;

            j+=2;
        }
    }

    /*
      INIT position rotors
      */
    pos_r1 = QString_to_int(this->zoneRotors->getRotor(1)->getLabelMid()->text());
    pos_r2 = QString_to_int(this->zoneRotors->getRotor(2)->getLabelMid()->text());
    pos_r3 = QString_to_int(this->zoneRotors->getRotor(3)->getLabelMid()->text());


}

void MainWindow::load_enigma(int in)
{
    int resultat = traitement(rotor1,rotor2,rotor3,refl,plugb,&pos_r1,&pos_r2,&pos_r3,in,nb_permutations);
    this->zoneLightBoard->light(resultat);
    this->zoneRotors->refresh(int_to_QString(pos_r1), int_to_QString(pos_r2), int_to_QString(pos_r3));
    this->log->setText(log->text()+int_to_char(resultat,0));
}


void MainWindow::keyPressEvent(QKeyEvent * e)
{
    QString recup = e->text();
    int i_recup = QString_to_int(recup);
    if( (i_recup >= 0) && (i_recup <= 25))
    {
        load_enigma(i_recup);
    }

}

/*
  Déclanchée lorsque que l'on presse f2 ou bien que l'on clique sur "Nouveau". Doit permettre une ré-initialisation
  */
void MainWindow::reload()
{
    int reponse = QMessageBox::question(this, "Voulez-vous vraiment recommencer?", "Voulez-vous vraiment recommencer?", QMessageBox::Yes, QMessageBox::No);
    if(reponse == QMessageBox::Yes)
    {
        if(is_phase2)
        {
            is_phase2 = 0;
            this->valider->setVisible(true);
            this->send->setVisible(false);
            this->in->setText(this->log->text());
            this->log->setText("");
            this->zoneLightBoard->turnoff();
            this->zoneRotors->raz_rotors();
            this->zonePlugBoard->raz_plugs();
            reset_rotor_intern();
        }
    }
}

/*
  Déclanchée lorsque l'on presse f1 ou bien que l'on clique sur "Aide". Doit permettre l'affichage d'une pop-up d'aide contenant un texte explicitatif
  */
void MainWindow::help()
{
    QMessageBox::information(this, "Aide", "1- Entrer la position initiale de vos rotors. (Attention : le rotor numero 1 se trouve a droite)\n2- Entrer vos permutations. Attention, elles sont symétriques('a' donne 'e' implique 'e' donne 'a'). Il faut au moins 3 permutations differentes. Les permutations d'une lettre a elle-meme ne sont pas comptabilisees.En cas de conflit, la permutation valide la plus a gauche est gardee.\n3- Appuyer sur valider.\n4- Appuyer sur une lettre de votre clavier et la machine vous donnera son crytage !\n\nA noter : Enigma est symetrique, pour decoder un message, utilisez la meme position initiale et entrer le message crypter pour obtenir son decryptage.");
}
/*
  Déclanchée lors d'un clique sur "A propos". Doit permettre l'affichage d'une pop-up décrivant l'application
  */
void MainWindow::describe()
{
    QMessageBox::information(this, "A propos", "Auteurs : J. Benoits et V. Honore.\nSimulateur Enigma realise dans le cadre du projet annuel du Cursus Master en Ingenierie de 3e annee de licence.\nRealise a des fins pedagogiques uniquement.\n\nEnigma etait une machine de cryptage utilisee par les Allemands lors de la seconde guerre mondiale. Elle est l'icone du debut de la transformation de la cryptologie par le monde moderne.");
}

void MainWindow::free_and_quit()
{
    int reponse = QMessageBox::question(this, "Voulez-vous vraiment quitter?", "Voulez-vous vraiment quitter?", QMessageBox::Yes, QMessageBox::No);
    if(reponse == QMessageBox::Yes)
    {
        /*
      Partie GUI
      */
        zoneRotors->deleteLater();
        zoneLightBoard->deleteLater();
        zonePlugBoard->deleteLater();
        log->deleteLater();
        valider->deleteLater();
        layout_mainWindow->deleteLater();

        /*
      Partie interne
      */
        free(rotor1->sorties);
        free(rotor2->sorties);
        free(rotor3->sorties);
        free(refl->sorties);
        for (int i=0;i<10;i++)
            free(plugb->connexions[i]);
        free(plugb->connexions);

        free(rotor1);
        free(rotor2);
        free(rotor3);
        free(refl);
        free(plugb);


        emit free_ok();
    }
}


int MainWindow::QString_to_int(QString label)
{
    if( (label == "A") || (label == "a") )
    {
        return 0;
    }
    if( (label == "B") || (label == "b") )
    {
        return 1;
    }
    if( (label =="C") || (label == "c") )
    {
        return 2;
    }
    if( (label == "D") || (label == "d"))
    {
        return 3;
    }
    if( (label == "E") || (label == "e") )
    {
        return 4;
    }
    if( (label == "F")  || (label == "f"))
    {
        return 5;
    }
    if( (label ==("G")) || (label == "g"))
    {
        return 6;
    }
    if( (label==("H")) || (label == "h"))
    {
        return 7;
    }
    if( (label==("I")) || (label == "i"))
    {
        return 8;
    }
    if( (label==("J")) || (label == "j"))
    {
        return 9;
    }
    if( (label==("K")) || (label == "k"))
    {
        return 10;
    }
    if( (label==("L")) || (label == "l"))
    {
        return 11;
    }
    if( (label==("M")) || (label == "m"))
    {
        return 12;
    }
    if( (label==("N")) || (label == "n"))
    {
        return 13;
    }
    if( (label==("O")) || (label == "o"))
    {
        return 14;
    }
    if( (label==("P")) || (label == "p"))
    {
        return 15;
    }
    if( (label==("Q")) || (label == "q"))
    {
        return 16;
    }
    if( (label==("R")) || (label == "r"))
    {
        return 17;
    }
    if( (label==("S")) || (label == "s"))
    {
        return 18;
    }
    if( (label==("T")) || (label == "t"))
    {
        return 19;
    }
    if( (label==("U")) || (label == "u"))
    {
        return 20;
    }
    if( (label==("V")) || (label == "v"))
    {
        return 21;
    }
    if( (label==("W")) || (label == "w"))
    {
        return 22;
    }
    if( (label==("X")) || (label == "x"))
    {
        return 23;
    }
    if( (label==("Y")) || (label == "y"))
    {
        return 24;
    }
    if( (label==("Z")) || (label == "z"))
    {
        return 25;
    }
    return -1;
}

QString MainWindow::int_to_QString(int i)
{
    QString s = "err";
    if(i == 0)
    {
        return s = "A";
    }

    if(i == 1)
    {
        return s = "B";
    }

    if(i == 2)
    {
        return s = "C";
    }

    if(i == 3)
    {
        return s = "D";
    }

    if(i == 4)
    {
        return s = "E";
    }

    if(i == 5)
    {
        return s = "F";
    }
    if(i == 6)
    {
        return s = "G";
    }

    if(i == 7)
    {
        return s = "H";
    }

    if(i == 8)
    {
        return s = "I";
    }

    if(i == 9)
    {
        return s = "J";
    }

    if(i == 10)
    {
        return s = "K";
    }

    if(i == 11)
    {
        return s = "L";
    }

    if(i == 12)
    {
        return s = "M";
    }

    if(i == 13)
    {
        return s = "N";
    }

    if(i == 14)
    {
        return s = "O";
    }

    if(i == 15)
    {
        return s = "P";
    }

    if(i == 16)
    {
        return s = "Q";
    }

    if(i == 17)
    {
        return s = "R";
    }

    if(i == 18)
    {
        return s = "S";
    }

    if(i == 19)
    {
        return s = "T";
    }

    if(i == 20)
    {
        return s = "U";
    }

    if(i == 21)
    {
        return s = "V";
    }

    if(i == 22)
    {
        return s = "W";
    }

    if(i == 23)
    {
        return s = "X";
    }

    if(i == 24)
    {
        return s = "Y";
    }

    if(i == 25)
    {
        return s = "Z";
    }

    return s;
}

void MainWindow::reset_rotor_intern()
{
    rotor1->sorties[0]=4;
    rotor1->sorties[1]=10;
    rotor1->sorties[2]=12;
    rotor1->sorties[3]=5;
    rotor1->sorties[4]=11;
    rotor1->sorties[5]=6;
    rotor1->sorties[6]=3;
    rotor1->sorties[7]=16;
    rotor1->sorties[8]=21;
    rotor1->sorties[9]=25;
    rotor1->sorties[10]=13;
    rotor1->sorties[11]=19;
    rotor1->sorties[12]=14;
    rotor1->sorties[13]=22;
    rotor1->sorties[14]=24;
    rotor1->sorties[15]=7;
    rotor1->sorties[16]=23;
    rotor1->sorties[17]=20;
    rotor1->sorties[18]=18;
    rotor1->sorties[19]=15;
    rotor1->sorties[20]=0;
    rotor1->sorties[21]=8;
    rotor1->sorties[22]=1;
    rotor1->sorties[23]=17;
    rotor1->sorties[24]=2;
    rotor1->sorties[25]=9;


    /* permutations du rotor 2 */
    rotor2->sorties[0]=0;
    rotor2->sorties[1]=9;
    rotor2->sorties[2]=3;
    rotor2->sorties[3]=10;
    rotor2->sorties[4]=18;
    rotor2->sorties[5]=8;
    rotor2->sorties[6]=17;
    rotor2->sorties[7]=20;
    rotor2->sorties[8]=23;
    rotor2->sorties[9]=1;
    rotor2->sorties[10]=11;
    rotor2->sorties[11]=7;
    rotor2->sorties[12]=22;
    rotor2->sorties[13]=19;
    rotor2->sorties[14]=12;
    rotor2->sorties[15]=2;
    rotor2->sorties[16]=16;
    rotor2->sorties[17]=6;
    rotor2->sorties[18]=25;
    rotor2->sorties[19]=13;
    rotor2->sorties[20]=15;
    rotor2->sorties[21]=24;
    rotor2->sorties[22]=5;
    rotor2->sorties[23]=21;
    rotor2->sorties[24]=14;
    rotor2->sorties[25]=4;


    /* permutations du rotor 3 */
    rotor3->sorties[0]=1;
    rotor3->sorties[1]=3;
    rotor3->sorties[2]=5;
    rotor3->sorties[3]=7;
    rotor3->sorties[4]=9;
    rotor3->sorties[5]=11;
    rotor3->sorties[6]=2;
    rotor3->sorties[7]=15;
    rotor3->sorties[8]=17;
    rotor3->sorties[9]=19;
    rotor3->sorties[10]=23;
    rotor3->sorties[11]=21;
    rotor3->sorties[12]=25;
    rotor3->sorties[13]=13;
    rotor3->sorties[14]=24;
    rotor3->sorties[15]=4;
    rotor3->sorties[16]=8;
    rotor3->sorties[17]=22;
    rotor3->sorties[18]=6;
    rotor3->sorties[19]=0;
    rotor3->sorties[20]=10;
    rotor3->sorties[21]=12;
    rotor3->sorties[22]=20;
    rotor3->sorties[23]=18;
    rotor3->sorties[24]=16;
    rotor3->sorties[25]=14;
}
